const path = require('path');

module.exports = {
  meta: {
    type: 'problem',
    docs: {
      description: 'Ensure variable names are unique within their scope and file',
      category: 'Possible Errors',
      recommended: true,
    },
    schema: [],
    messages: {
      duplicateVar: 'Variable name "{{name}}" is already used in this {{scope}}.',
      similarVar: 'Variable name "{{name}}" is too similar to existing variable "{{existing}}".'
    }
  },

  create(context) {
    const declaredVars = new Map();
    const fileVars = new Set();

    function checkSimilarity(newName, existingNames) {
      const similarityThreshold = 0.8;
      for (const existing of existingNames) {
        const distance = levenshtein(newName, existing);
        const maxLength = Math.max(newName.length, existing.length);
        const similarity = 1 - distance / maxLength;
        if (similarity > similarityThreshold) {
          return existing;
        }
      }
      return null;
    }

    function levenshtein(a, b) {
      if (a.length === 0) return b.length;
      if (b.length === 0) return a.length;

      const matrix = [];
      for (let i = 0; i <= b.length; i++) {
        matrix[i] = [i];
      }
      for (let j = 0; j <= a.length; j++) {
        matrix[0][j] = j;
      }

      for (let i = 1; i <= b.length; i++) {
        for (let j = 1; j <= a.length; j++) {
          const cost = a[j - 1] === b[i - 1] ? 0 : 1;
          matrix[i][j] = Math.min(
            matrix[i - 1][j] + 1,
            matrix[i][j - 1] + 1,
            matrix[i - 1][j - 1] + cost
          );
        }
      }

      return matrix[b.length][a.length];
    }

    return {
      VariableDeclarator(node) {
        if (node.id.type === 'Identifier') {
          const varName = node.id.name;
          const currentScope = context.getScope();

          // Check scope uniqueness
          if (declaredVars.has(varName)) {
            const existingScope = declaredVars.get(varName);
            if (existingScope === currentScope) {
              context.report({
                node: node.id,
                messageId: 'duplicateVar',
                data: {
                  name: varName,
                  scope: 'scope'
                }
              });
            }
          }

          // Check file uniqueness
          if (fileVars.has(varName)) {
            context.report({
              node: node.id,
              messageId: 'duplicateVar',
              data: {
                name: varName,
                scope: 'file'
              }
            });
          }

          // Check similarity
          const similarVar = checkSimilarity(varName, [...fileVars]);
          if (similarVar) {
            context.report({
              node: node.id,
              messageId: 'similarVar',
              data: {
                name: varName,
                existing: similarVar
              }
            });
          }

          declaredVars.set(varName, currentScope);
          fileVars.add(varName);
        }
      },

      'Program:exit'() {
        declaredVars.clear();
      }
    };
  }
};